home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 4
/
Apprentice-Release4.iso
/
Languages
/
MacQForth 1.0
/
source
/
QForth.plain
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Text File
|
1995-03-28
|
47.0 KB
|
1,199 lines
|
[
TEXT/ALFA
]
\ QForth plain, 8-bit 65C02 simulator to run QForth 1.1, 03-03-95
\
\ last modification, 03-03-95
\
\
\ This should run under almost any 32-bit Forth system. To run on a
\ 16-bit system change the 4 * in places indicated to a 2 *
\
\ To be fully functional, you need to write the code for all lines marked
\ with a **** . This is mainly graphics and disk access.
\
\
\ Copyright (c) 1995, Ronald T. Kneusel, all rights reserved.
\
\
\ Permission given to modify this code provided that credit is given
\ where credit is due.
\
\
\ Internet: kneusel@msupa.pa.msu.edu
\ kneusel@studsys.mscs.mu.edu
\ rtk@herman.gem.valpo.edu
\
\ Mail: 8725 West Burdick Ave.
\ Milwaukee, WI 53227
\ USA
\ (414) 545-7557
\
\ Note: This code is falling out of step with MacQForth. Look at both
\ files for a complete implementation.
\
\ ===========================================================================
\ Section: Memory Access and Frequently used Words
hex \ switch to hexadecimal
\ Define memory, 64K = 65536 bytes
variable $0000 10000 allot \ $0000 is base of memory, allot 64K
\ Memory access words, $@ and $!
: $@ ( address -- value ) $0000 + c@ ;
: $! ( value address -- ) $0000 + c! ;
\ Define accumulator, X & Y registers, stack pointer, and program counter
variable A variable X variable Y
variable S variable PC variable oldA \ for overflow detection
( Helpful words to know ) \ make all of these inline in final version
: fetch ( -- ) \ get & increment PC
PC @ dup $@ swap 1+ PC ! ;
: >addr ( lo hi -- addr ) 100 * + ; \ make an address
: a>v ( -- n ) fetch fetch >addr $@ ; ( get value at abs. addr )
: addr> ( -- a ) fetch fetch >addr ; ( leave address on stack )
: z>v ( -- n ) fetch $@ ; ( get value at zero addr )
: zaddr> ( -- a ) fetch ; ( leave zero page address on stack )
: push ( n -- ) ( push stack to system stack )
S @ 1- dup 100 < if drop 1ff then dup S ! $! ;
: pull ( -- n ) ( pull from system stack )
S @ dup $@ swap 1+ dup 1ff > if drop 1ff then S ! ;
: pushPC ( -- ) ( push PC on system stack ) \ assumes a 32-bit forth
PC @ 1- PC ! PC 2+ c@ push PC 3 + c@ push ;
\ address mode access words
variable addr \ holds memory address most recently accessed
: imm. fetch ;
: zpg. fetch dup addr ! $@ ;
: zpx. fetch X @ + dup addr ! $@ ;
: zpi. fetch dup 1+ $@ swap $@ swap 100 * + dup addr ! $@ ;
: abs. fetch fetch 100 * + dup addr ! $@ ;
: abx. fetch fetch 100 * + X @ + dup addr ! $@ ;
: aby. fetch fetch 100 * + Y @ + dup addr ! $@ ;
: inx. fetch X @ + dup 1+ $@ swap $@ swap 100 * + dup addr ! $@ ;
: iny. fetch dup 1+ $@ swap $@ swap 100 * + Y @ + dup addr ! $@ ;
\ Processor status flags are boolean variables
variable #N \ negative
variable #Z \ zero
variable #C \ carry
variable #I \ interrupt
variable #D \ decimal mode
variable #V \ overflow
\ **** Update processor status ****
: set -1 swap ! ;
: unset 0 swap ! ;
: @v @ if 1 else 0 then ; \ for use in ADC, SBC and PHP
: v! swap 0= if 0 else -1 then swap ! ; \ for use in ROR and LSR
\ Relative branch instructions
: branch0 ( n -- ) \ unset PC to forward or backward branch
dup 80 < if
PC @ + PC ! \ forward branch
else
100 swap - PC @ swap - PC ! \ backward branch
then
;
\ Section: 65C02 Instructions
\ ADC - Add to Accumulator with Carry
\ set processor status flags
: psADC ( v -- )
>r r@ FF > if r@ 100 - A ! #C set else #C unset then \ carry
r@ 0= if #Z set else #Z unset then \ zero
r@ 7F > if #N set else #N unset then \ negative
r> 80 and oldA @ 80 and <> if #V set else #V unset then \ overflow
;
: doADC
A @ dup oldA ! + #C @v + dup A ! psADC
;
\ code
: $69 imm. doADC ; \ immediate
: $65 zpg. doADC ; \ zero page
: $75 zpx. doADC ; \ zero page,X
: $72 zpi. doADC ; \ zero page indirect
: $6D abs. doADC ; \ absolute
: $7D abx. doADC ; \ absolute,X
: $79 aby. doADC ; \ absolute,Y
: $61 inx. doADC ; \ indirect,X
: $71 iny. doADC ; \ indirect,Y
\ AND - and Memory with Accumulator
: psAND
dup 0= if #Z set else #Z unset then \ zero
7F > if #N set else #N unset then ; \ negative
: doAND A @ and dup A ! psAND ;
: $29 imm. doAND ; \ immediate
: $25 zpg. doAND ; \ zero page
: $32 zpi. doAND ; \ zero page indirect
: $35 zpx. doAND ; \ zero page,X
: $2D abs. doAND ; \ absolute
: $3D abx. doAND ; \ absolute,X
: $39 aby. doAND ; \ absolute,Y
: $21 inx. doAND ; \ indirect,X
: $31 iny. doAND ; \ indirect,Y
\ ASL - Accumulator Shift Left
: psASL dup FF > if 100 - #C set else #C unset then
dup 0= if #Z set else #Z unset then
dup 7F > if #N set else #N unset then
;
: $0A A @ 2 * psASL A ! ; \ accumulator
: $06 zpg. 2 * psASL addr @ $! ; \ zero page
: $16 zpx. 2 * psASL addr @ $! ; \ zero page,X
: $0E abs. 2 * psASL addr @ $! ; \ absolute
: $1E abx. 2 * psASL addr @ $! ; \ absolute,X
\ BCC - Branch on Carry Clear
: $90 imm. #C @ if drop else branch0 then ;
\ BCS - Branch on Carry Set
: $B0 imm. #C @ if branch0 else drop then ;
\ BEQ - Branch on result Equal to Zero
: $F0 imm. #Z @ if branch0 else drop then ;
\ BIT - Test Bits in Memory with Accumulator
: doBIT ( n -- ) \ perform a BIT operation
dup dup
80 and 0= if #N unset else #N set then
40 and 0= if #V unset else #N set then
A @ and 0= if #Z set else #Z unset then ;
: $89 imm. A @ and 0= if #Z set else #Z unset then ;
: $24 zpg. doBIT ;
: $34 zpx. doBIT ;
: $2C abs. doBIT ;
: $3C abx. doBIT ;
\ BMI - Branch on result minus
: $30 imm. #N @ if branch0 else drop then ;
\ BNE - Branch on result not equal to zero
: $D0 imm. #Z @ if drop else branch0 then ;
\ BPL - Branch on result plus
: $10 imm. #N @ if drop else branch0 then ;
\ BRA - Branch relative always
: $80 imm. branch0 ;
\ BRK - Break - enters the program whose address is $FFFE lo $FFFF hi
: $00 FFFE $@ FFFF $@ 100 * + PC ! ;
\ BVC - Branch on overflow clear
: $50 imm. #V @ if drop else branch0 then ;
\ BVS - Branch on overflow set
: $70 imm. #V @ if branch0 else drop then ;
\ CLC - Clear Carry Flag
: $18 #C unset ;
\ CLD - Clear Decimal Flag
: $D8 #D unset ;
\ CLI - Clear Interrupt Disable
: $58 #I unset ;
\ CLV - Clear overflow flag
: $B8 #V unset ;
\ CMP - Compare Memory and Accumulator
: doCMP
dup A @ swap < if #N set #Z unset #C unset drop else
dup A @ = if #Z set #C set #N unset drop else
A @ swap > if #C set #Z unset #N unset then
then then ;
: $C9 imm. doCMP ;
: $C5 zpg. doCMP ;
: $D5 zpx. doCMP ;
: $D2 zpi. doCMP ;
: $CD abs. doCMP ;
: $DD abx. doCMP ;
: $D9 aby. doCMP ;
: $C1 inx. doCMP ;
: $D1 iny. doCMP ;
\ CPX - Compare Memory and X
: doCPX
dup X @ swap < if #N set #Z unset #C unset drop else
dup X @ = if #Z set #C set #N unset drop else
X @ swap > if #C set #Z unset #N unset then
then then ;
: $E0 imm. doCPX ;
: $E4 zpg. doCPX ;
: $EC abs. doCPX ;
\ CPY - Compare Memory and Y
: doCPY
dup Y @ swap < if #N set #Z unset #C unset drop else
dup Y @ = if #Z set #C set #N unset drop else
Y @ swap > if #C set #Z unset #N unset then
then then ;
: $C0 imm. doCPY ;
: $C4 zpg. doCPY ;
: $CC abs. doCPY ;
\ DEA - Decrement Accumulator
: $3A A @ 1-
dup -1 = if drop FF A ! FF then
dup 0= if #Z set else #Z unset then
dup 7F > if #N set else #N unset then
A ! ;
\ DEC - Decrement Memory by One
: doDEC 1-
dup -1 = if drop FF then
dup 0= if #Z set else #Z unset then
dup 7F > if #N set else #N unset then
addr @ $! ;
: $C6 zpg. doDEC ;
: $D6 zpx. doDEC ;
: $CE abs. doDEC ;
: $DE abx. doDEC ;
\ DEX - Decrement X by one
: $CA X @ 1-
dup -1 = if drop FF X ! FF then
dup 0= if #Z set else #Z unset then
dup 7F > if #N set else #N unset then
X ! ;
\ DEY - Decrement Y by one
: $88 Y @ 1-
dup -1 = if drop FF Y ! FF then
dup 0= if #Z set else #Z unset then
dup 7F > if #N set else #N unset then
Y ! ;
\ EOR - Exclusive OR Memory and Accumulator
: psEOR
dup 0= if #Z set else #Z unset then \ zero
7F > if #N set else #N unset then ; \ negative
: doEOR A @ xor dup A ! psEOR ;
: $49 imm. doEOR ; \ immediate
: $45 zpg. doEOR ; \ zero page
: $52 zpi. doEOR ; \ zero page indirect
: $55 zpx. doEOR ; \ zero page,X
: $4D abs. doEOR ; \ absolute
: $5D abx. doEOR ; \ absolute,X
: $59 aby. doEOR ; \ absolute,Y
: $41 inx. doEOR ; \ indirect,X
: $51 iny. doEOR ; \ indirect,Y
\ INC - Increment Memory by One
: doINC 1+
dup 100 = if drop 0 then
dup 0= if #Z set else #Z unset then
dup 7F > if #N set else #N unset then
addr @ $! ;
: $E6 zpg. doINC ;
: $F6 zpx. doINC ;
: $EE abs. doINC ;
: $FE abx. doINC ;
\ INA - Increment A by one
: $1A A @ 1+
dup 100 = if drop 0 A ! 0 then
dup 0= if #Z set else #Z unset then
dup 7F > if #N set else #N unset then
A ! ;
\ INX - Increment X by one
: $E8 X @ 1+
dup 100 = if drop 0 X ! 0 then
dup 0= if #Z set else #Z unset then
dup 7F > if #N set else #N unset then
X ! ;
\ INY - Increment Y by one
: $C8 Y @ 1+
dup 100 = if drop 0 Y ! 0 then
dup 0= if #Z set else #Z unset then
dup 7F > if #N set else #N unset then
Y ! ;
\ JMP - Jump
: $4C fetch fetch 100 * + PC ! ;
: $6C fetch fetch 100 * + dup 1+ $@ swap $@ swap 100 * + PC ! ;
: $7C fetch fetch 100 * + X @ + dup 1+ $@ swap $@ swap 100 * + PC ! ;
\ JSR - Jump to subroutine
: $20 fetch fetch pushPC >addr PC ! ;
\ LDA - Load the Accumulator
: psLDA
dup 0= if #Z set else #Z unset then
7F > if #N set else #N unset then ;
: doLDA dup psLDA A ! ;
: $A9 imm. doLDA ; \ immediate
: $A5 zpg. doLDA ; \ zero page
: $B2 zpi. doLDA ; \ zero page indirect
: $B5 zpx. doLDA ; \ zero page,X
: $AD abs. doLDA ; \ absolute
: $BD abx. doLDA ; \ absolute,X
: $B9 aby. doLDA ; \ absolute,Y
: $A1 inx. doLDA ; \ indirect,X
: $B1 iny. doLDA ; \ indirect,Y
\ LDX - Load the X register
: psLDX
dup 0= if #Z set else #Z unset then
7F > if #N set else #N unset then ;
: doLDX dup psLDX X ! ;
: $A2 imm. doLDX ; \ immediate
: $A6 zpg. doLDX ; \ zero page
: $B6 fetch Y @ + $@ doLDX ; \ zero page,Y
: $AE abs. doLDX ; \ absolute
: $BE fetch fetch >addr Y @ + $@ doLDX ; \ absolute,Y
\ LDY - Load the Y register
: psLDY
dup 0= if #Z set else #Z unset then
7F > if #N set else #N unset then ;
: doLDY dup psLDY Y ! ;
: $A0 imm. doLDY ; \ immediate
: $A4 zpg. doLDY ; \ zero page
: $B4 zpx. doLDY ; \ zero page,X
: $AC abs. doLDY ; \ absolute
: $BC abx. doLDY ; \ absolute,X
\ LSR - Shift right
: psLSR
dup 1 and #C v! 2/
dup 0= if #Z set else #Z unset then
#N unset ;
: $4A A @ psASL A ! ; \ accumulator
: $46 zpg. psASL addr @ $! ; \ zero page
: $56 zpx. psASL addr @ $! ; \ zero page,X
: $4E abs. psASL addr @ $! ; \ absolute
: $5E abx. psASL addr @ $! ; \ absolute,X
\ NOP - No Operation
: $EA ;
\ ORA - OR memory with Accumulator
: psORA
dup 0= if #Z set else #Z unset then \ zero
7F > if #N set else #N unset then ; \ negative
: doORA A @ or dup A ! psORA ;
: $09 imm. doORA ; \ immediate
: $05 zpg. doORA ; \ zero page
: $12 zpi. doORA ; \ zero page indirect
: $15 zpx. doORA ; \ zero page,X
: $0D abs. doORA ; \ absolute
: $1D abx. doORA ; \ absolute,X
: $19 aby. doORA ; \ absolute,Y
: $01 inx. doORA ; \ indirect,X
: $11 iny. doORA ; \ indirect,Y
\ PHA - Push Accumulator on Stack
: $48 A @ push ;
\ PHP - Push Processor Status on Stack
: $08
#N @v 80 * #V @v 40 * + #D @v 8 * + #I @v 4 * + #Z @v 2 * + #C @v +
push ;
\ PHX - Push X on Stack
: $DA X @ push ;
\ PHY - Push Y on Stack
: $5A Y @ push ;
\ PLA - Pull A from Stack
: $68 pull dup A ! psORA ; \ call psORA to set the flags
\ PLP - Pull processor status from Stack
: $28 pull
dup 80 and 0= if #N unset else #N set then
dup 40 and 0= if #V unset else #V set then
dup 8 and 0= if #D unset else #D set then
dup 4 and 0= if #I unset else #I set then
dup 2 and 0= if #Z unset else #Z set then
1 and 0= if #C unset else #C set then
;
\ PLX - Pull X from stack
: $FA pull dup X ! psORA ; \ as in PLA
\ PLY - Pull Y from stack
: $7A pull dup Y ! psORA ; \ as in PLA
\ ROL - Rotate Accumulator or Memory left
: psROL
dup FF > if 100 - #C set else #C unset then
dup 0= if #Z set else #Z unset then
dup 7F > if #N set else #N unset then ;
: doROL 2 * #C @v + psROL ;
: $2A A @ doROL A ! ; \ accumulator
: $26 zpg. doROL addr @ $! ; \ zero page
: $36 zpx. doROL addr @ $! ; \ zero page,X
: $2E abs. doROL addr @ $! ; \ absolute
: $3E abx. doROL addr @ $! ; \ absolute,X
\ ROR - Rotate Accumulator or Memory right
: psROR
dup 0= if #Z set else #Z unset then
dup 7F > if #N set else #N unset then ;
: doROR dup 1 and swap 2/ #C @v 80 * + swap #C v! psROR ;
: $6A A @ doROR A ! ; \ accumulator
: $66 zpg. doROR addr @ $! ; \ zero page
: $76 zpx. doROR addr @ $! ; \ zero page,X
: $6E abs. doROR addr @ $! ; \ absolute
: $7E abx. doROR addr @ $! ; \ absolute,X
\ RTI - Return from Interrupt
: $40 ; \ interrupts not enabled
\ RTS - Return from subroutine
: $60 pull pull >addr 1+ PC ! ;
\ SBC - Subtract from Accumulator with Carry
: psSBC ( v -- )
>r r@ 0 < if r@ 100 + A ! #C unset else #C set then \ carry
r@ 0= if #Z set else #Z unset then \ zero
r@ 7F > if #N set else #N unset then \ negative
r> 80 and oldA @ 80 and <> if #V set else #V unset then \ overflow
;
: doSBC
A @ dup oldA ! swap - #C @v 1 xor - dup A ! psSBC
;
: $E9 imm. doSBC ; \ immediate
: $E5 zpg. doSBC ; \ zero page
: $F2 zpi. doSBC ; \ zero page indirect
: $F5 zpx. doSBC ; \ zero page,X
: $ED abs. doSBC ; \ absolute
: $FD abx. doSBC ; \ absolute,X
: $F9 aby. doADC ; \ absolute,Y
: $E1 inx. doADC ; \ indirect,X
: $F1 iny. doADC ; \ indirect,Y
\ SEC - Set Carry Flag
: $38 #C set ;
\ SED - Set Decimal Mode
: $F8 #D set
." Warning! Decimal mode set but not currently implemented." cr ;
\ SEI - Set Interrupt Disable
: $78 ; \ interrupts are not enabled
\ STA - Store Accumulator in Memory
: doSTA drop A @ addr @ $! ;
: $85 zpg. doSTA ; \ zero page
: $92 zpi. doSTA ; \ zero page indirect
: $95 zpx. doSTA ; \ zero page,X
: $8D abs. doSTA ; \ absolute
: $9D abx. doSTA ; \ absolute,X
: $99 aby. doSTA ; \ absolute,Y
: $81 inx. doSTA ; \ indirect,X
: $91 iny. doSTA ; \ indirect,Y
\ STX - Store X in Memory
: $86 zpg. drop X @ addr @ $! ; \ zero page
: $96 X @ fetch Y @ + $! ; \ zero page,Y
: $8E abs. drop X @ addr @ $! ; \ absolute
\ STY - Store Y in Memory
: $84 zpg. drop Y @ addr @ $! ; \ zero page
: $94 zpx. drop Y @ addr @ $! ; \ zero page,X
: $8C abs. drop Y @ addr @ $! ; \ absolute
\ TAX - Transfer Accumulator to Index X
: $AA A @ dup X ! dup 0= if #Z set else #Z unset then
7F > if #N set else #N unset then ;
\ TAY - Transfer Accumulator to Index Y
: $A8 A @ dup Y ! dup 0= if #Z set else #Z unset then
7F > if #N set else #N unset then ;
\ TSX - Transfer stack pointer to X
: $BA S @ 100 - dup X ! dup 0= if #Z set else #Z unset then
7F > if #N set else #N unset then ;
\ TXA - Transfer X to A
: $8A X @ dup A ! dup 0= if #Z set else #Z unset then
7F > if #N set else #N unset then ;
\ TXS - Transfer X to Stack
: $9A X @ 100 + S ! ;
\ TYA - Transfer Y to A
: $98 Y @ dup A ! dup 0= if #Z set else #Z unset then
7F > if #N set else #N unset then ;
\ STZ - Store zero
: $9C abs. drop 0 addr @ $! ; \ absolute
: $9E abx. drop 0 addr @ $! ; \ absolute,X
: $64 zpg. drop 0 addr @ $! ; \ zer len -- ec ) ; \ ****
: bytesReadf0 ; \ return number of bytes read during last read ****
: bytesReadf1 ; \ ****
: bytesReadf2 ; \ ****
: fill&clear \ fill buffer with $20 and clear high bits to speed
\ loading.
\ fill remainder of buffer with spaces
2000 bytesReadf0 1000 + do
20 i $!
loop
\ clear the hi-bit of the data
2000 1000 do
i $@ 7F and i $!
loop
;
: pdCA \ read bytes
paramAddr 2+ c@ paramAddr 3 + c@ 100 * + $0000 + \ address of buffer
paramAddr 4 + c@ paramAddr 5 + c@ 100 * + \ requested length
paramAddr 1+ c@ \ reference number
dup 0= if drop readf0 else
dup 1 = if drop readf1 else \ read appropriate file
dup 2 = if drop readf2 else
drop readf0 then then then
err \ handle error code
paramAddr 1+ c@
dup 0= if drop bytesReadf0 else
dup 1 = if drop bytesReadf1 else \ fill in bytes read
dup 2 = if drop bytesReadf2 else
drop bytesReadf0 then then then
pushT !
pushT 3 + c@ paramAddr 6 + c! \ lo
pushT 2+ c@ paramAddr 7 + c! \ hi
paramAddr 1+ c@ 3 = if fill&clear then \ set up for 'read'
;
: writef0 ( addr len -- ) ; \ write len bytes from addr to file 0 ****
: writef1 ; \ ****
: writef2 ; \ ****
: pdCB \ write bytes
paramAddr 2+ c@ paramAddr 3 + c@ 100 * + $0000 + \ address of buffer
paramAddr 4 + c@ paramAddr 5 + c@ 100 * + \ requested length
paramAddr 1+ c@ \ reference number
dup 0= if drop writef0 else
dup 1 = if drop writef1 else \ read appropriate file
drop writef2 then then
err \ handle error code
paramAddr 4 + c@ paramAddr 6 + c! \ lo bytes written = bytes requested
paramAddr 5 + c@ paramAddr 7 + c! \ hi
;
: closef0 ; \ close file 0 ****
: closef1 ; \ ****
: closef2 ; \ ****
: pdCC \ close a file
paramAddr 1+ c@ \ reference number
dup 0= if drop closef0 else
dup 1 = if drop closef1 else \ close the file
2 = if closef2 else
closef0 then then then \ 'read' uses reference number 3
err \ return code to A
;
: moveTof0 ( byte# -- ec ) ; \ move file 0 pointer to byte # ****
: moveTof1 ; \ ****
: moveTof2 ; \ ****
: pdCE \ set file position
paramAddr 4 + c@ 10000 * \ file position
paramAddr 3 + c@ 100 * +
paramAddr 2+ c@ +
paramAddr 1+ c@ \ reference number
dup 0= if drop moveTof0 else
dup 1 = if drop moveTof1 else \ position
drop moveTof2 then then
err
;
: $FF
pull pull >addr 1+ dup >r $@ func ! \ get command code
r@ 1+ $@ r@ 2+ $@ 100 * + params ! \ get parameter table address
r> 3 + PC ! \ set PC to next instruction
\ do the command
func @
dup C0 = if drop pdC0 else \ create
dup C1 = if drop pdC1 else \ destroy
dup C4 = if drop pdC4 else \ info
dup C8 = if drop pdC8 else \ open
dup CA = if drop pdCA else \ read
dup CB = if drop pdCB else \ write
dup CC = if drop pdCC else \ close
dup CE = if drop pdCE else \ position
dup 65 = if drop bye else \ bye, quit program
." ProDOS MLI error: Unknown function, code = " . cr quit
then then then then then then then then then
A @ 0= if #C unset #Z set else #C set #Z unset then \ signal an error
\ PC already set properly, so just return
;
\ Monitor routines and locations
: $DB \ trap CH word, set horizontal position
Y @ \ set horizontal cursor position to the value in Y ****
;
: $DF \ trap CV word, set vertical position
Y @ \ set vertical cursor position to the value in Y ****
;
: $E7 \ trap $C300 - clear the screen
page ;
: del \ handle a backspace or delete character
8 emit \ should work on most terminals ****
;
: 80? ; \ true if cursor position at 80 ****
: $F3 \ cout - output character in A
80? if cr then \ newline if 80 characters out on this line
A @ 7F and \ QForth sets hi bit, clear it
dup 7F = if drop del else \ delete
dup 08 = if drop del else \ backspace
dup 0d = if drop space cr else \ return
dup 1F > if emit else drop \ alphanumeric
then then then then
;
: .r ( n d -- ) \ ****
drop . ; \ print n in justified in d spaces in current base
: $C7 \ hex - output character in A as two hex digits
@xy drop 1E8 = if cr then
A @ 10 < if 30 emit A @ 1 .r else A @ 2 .r then
;
: random ( n -- m ) 0 ; \ return a random number from 0 to n-1 ****
: $CB \ put a random number in FF8E and FF8F
100 random FF8F $! 100 random FF8E $! ;
: $F7 \ output a cr
space cr ;
: $FB \ get a key to A
key 80 or A ! ;
: depthQF \ depth of QForth stack
F4 $@ ;
variable xGR \ hold current graphics coordinates
variable yGR
: gotoxy ( x y -- ) ; \ move drawing pen to x,y ****
: lineto ( x y -- ) ; \ line from current position to x,y ****
: putPen \ restore graphics pen position
xGR @ yGR @ gotoxy ;
: savePen \ store graphics pen position
@xy yGR ! xGR ! ;
: $EB \ LineTo
depthQF 1 > if \ at least two values
@xy putPen \ save current position and move to old graphics position
popQF popQF swap lineto \ move
savePen gotoxy \ store new graphics position
then
;
: $EF \ MoveTo
depthQF 1 > if
@xy putPen
popQF popQF swap gotoxy
savePen gotoxy
then
;
: red ; \ set the appropriate drawing color ****
: black ; \ ****
: yellow ; \ ****
: green ; \ ****
: blue ; \ ****
: white ; \ ****
: cyan ; \ ****
: magenta ; \ ****
: $E3 \ set drawing color
depthQF 0 > if
popQF
dup 0 = if drop black else
dup 1 = if drop red else
dup 2 = if drop green else
dup 3 = if drop blue else
dup 4 = if drop cyan else
dup 5 = if drop magenta else
dup 6 = if drop yellow else
7 = if drop white else
black then then then then then then
then then then
;
: $D7 \ plot a point, faster than using QForth code
depthQF 1 > if
@xy popQF dup yGR ! popQF dup xGR ! swap
2dup gotoxy lineto
gotoxy
then
;
: $D3 \ get mouse position and button status ****
\ get mouse position and button status (0,-1)
0= if 0 pushQF else FFFF pushQF then \ push button status on stack
;
\ Section: System Monitor
\
\ System monitor - $FFF0
\
: 'type ; \ read the next word and compile the characters in to a single
\ 32-bit word with a space at the end. Something needs to be done
\ here for 16-bit Forths.
\
\ ex. 'type ABC should return 41424320 ****
variable buff 4C allot \ a small input buffer
'type ADC variable mnemonics \ table of instruction names
'type AND , 'type ASL , 'type BCC , 'type BCS , 'type BEQ ,
'type BIT , 'type BMI , 'type BNE , 'type BPL , 'type BRA ,
'type BRK , 'type BVC , 'type BVS , 'type CLC , 'type CLD ,
'type CLI , 'type CLV , 'type CMP , 'type CPX , 'type CPY ,
'type DEA , 'type DEC , 'type DEX , 'type DEY , 'type EOR ,
'type INA , 'type INC , 'type INX , 'type INY , 'type JMP ,
'type JSR , 'type LDA , 'type LDX , 'type LDY , 'type LSR ,
'type NOP , 'type ORA , 'type PHA , 'type PHP , 'type PHX ,
'type PHY , 'type PLA , 'type PLP , 'type PLX , 'type PLY ,
'type ROL , 'type ROR , 'type RTI , 'type RTS , 'type SBC ,
'type SEC , 'type SED , 'type SEI , 'type STA , 'type STX ,
'type STY , 'type STZ , 'type TAX , 'type TAY , 'type TRB ,
'type TSB , 'type TSX , 'type TXA , 'type TXS , 'type TYA ,
'type ??? ,
\ listing table, each entry is 4 bytes long <00><00><instruction#><mode>
\ 16-bit Forths are okay here, but need to modify access word below
\ <mode>= 00 - implied, 1 byte
\ 01 - immediate, 2 byte
\ 02 - absolute, 3 byte
\ 03 - zero page, 2 byte
\ 04 - ABS,X, 3 byte
\ 05 - ZPG,X, 2 byte
\ 06 - (IND,X), 2 byte
\ 07 - ABS(IND,X), 3 byte
\ 08 - (IND),Y, 2 byte
\ 09 - (ZPG), 2 byte
\ 0A - (ABS), 3 byte
\ 0B - ABS,Y, 3 byte
\ 0C - ZPG,Y, 2 byte
variable list 0C00 list !
2606 , 4300 , 4300 , 3E03 , 2603 , 0303 , 4300 , 2800 , 2601 , 0300 ,
4300 , 3E02 , 2602 , 0302 , 4300 , \ row 00
0A01 , 2608 , 2609 , 4300 , 3D03 , 2606 , 0306 , 4300 , 0F00 , 260B ,
1B00 , 4300 , 3D02 , 2604 , 0304 , 4300 , \ row 01
2002 , 0206 , 4300 , 4300 , 0703 , 0203 , 2F03 , 4300 , 2C00 , 0201 ,
2F00 , 4300 , 0702 , 0202 , 2F02 , 4300 , \ row 02
0801 , 0208 , 0209 , 4300 , 0705 , 0205 , 2F05 , 4300 , 3400 , 020B ,
1600 , 4300 , 0704 , 0204 , 2F04 , 4300 , \ row 03
3100 , 1A06 , 4300 , 4300 , 4300 , 1A03 , 2403 , 4300 , 2700 , 1A01 ,
2400 , 4300 , 1F02 , 1A02 , 2402 , 4300 , \ row 04
0D01 , 1A08 , 1A09 , 4300 , 4300 , 1A05 , 2405 , 4300 , 1100 , 1A0B ,
2A00 , 4300 , 4300 , 1A04 , 2404 , 4300 , \ row 05
3200 , 0106 , 4300 , 4300 , 3A03 , 0103 , 3003 , 4300 , 2B00 , 0101 ,
3000 , 4300 , 1F0A , 0102 , 3002 , 4300 , \ row 06
0E01 , 0106 , 0109 , 4300 , 3A05 , 0105 , 3005 , 4300 , 3600 , 010B ,
2E00 , 4300 , 1F07 , 0104 , 3004 , 4300 , \ row 07
0B01 , 3706 , 4300 , 4300 , 3903 , 3703 , 3803 , 4300 , 1900 , 0701 ,
4000 , 4300 , 3902 , 3702 , 3802 , 4300 , \ row 08
0401 , 3708 , 3709 , 4300 , 3905 , 3705 , 380C , 4300 , 4200 , 370B ,
4100 , 4300 , 3A02 , 3704 , 3A04 , 4300 , \ row 09
2301 , 2106 , 2201 , 4300 , 2303 , 2103 , 2203 , 4300 , 3C00 , 2101 ,
3B00 , 4300 , 2302 , 2102 , 2202 , 4300 , \ row 0A
0501 , 2108 , 2109 , 4300 , 2305 , 2105 , 220C , 4300 , 1200 , 210B ,
3F00 , 4300 , 2304 , 2104 , 220B , 4300 , \ row 0B
1501 , 1306 , 4300 , 4300 , 1503 , 1303 , 1703 , 4300 , 1E00 , 1301 ,
1800 , 4300 , 1502 , 1302 , 1702 , 4300 , \ row 0C
0901 , 1308 , 1309 , 4300 , 4300 , 1305 , 1705 , 4300 , 1000 , 130B ,
2900 , 4300 , 4300 , 1304 , 1704 , 4300 , \ row 0D
1401 , 3306 , 4300 , 4300 , 1403 , 3303 , 1C03 , 4300 , 1D00 , 3301 ,
2500 , 4300 , 1402 , 3302 , 1C02 , 4300 , \ row 0E
0601 , 3308 , 3309 , 4300 , 4300 , 3305 , 1C05 , 4300 , 3500 , 330B ,
2D00 , 4300 , 4300 , 3304 , 1C04 , 4300 , \ row 0F
: uppercase \ make a character uppercase
dup dup 60 > swap 7B < and if 20 - then ;
: chars ( buff maxlen -- length ) \ returns the length of the line
0 do dup i + c@ 0= if drop i FF else 1 then +loop ;
variable buff2 4C allot \ temporary buffer
variable k \ index
: killSpaces \ remove spaces from the input line
0 k !
buff 50 chars 1+ 0 do
buff i + c@ dup 20 <> if
uppercase buff2 k @ + c! \ save in temporary buffer
k @ 1+ k ! \ increment k
else drop then
loop
buff2 50 chars 1+ 0 do
buff2 i + c@ buff i + c! \ put in original buffer
loop ;
variable num 4C allot \ conversion buffer
variable endchar \ stop character
variable buffaddr \ buffer address
: getNumber ( addr end-char -- n ) \ make a string a number
1 k ! \ use k defined above in killSpaces
20 num c! \ initial blank
endchar ! buffaddr ! \ save end character and buffer address
begin
buffaddr @ c@ endchar @ <> \ haven't reached match character
while
buffaddr @ c@ uppercase
num k @ + c! \ copy character to num
buffaddr @ 1+ buffaddr ! \ increment buffer pointer
k @ 1+ k ! \ and index pointer
repeat
20 num k @ + c! \ add final blank
0 num k @ 1+ + c! \ and null
\ convert the string <bl><text><bl> in num to a number ****
;
variable lines \ number of lines listed
variable listAddr \ address
variable aLabel \ holds a compressed label
: printLabel \ print an instruction label
1- 4 * mnemonics + @ \ get the label
aLabel ! \ save it
aLabel c@ emit aLabel 1+ c@ emit aLabel 2+ c@ emit \ print it
space ;
: instSize \ return instruction size in bytes
dup 0 = if drop 1 else \ implied
dup 1 = if drop 2 else \ immediate
dup 2 = if drop 3 else \ absolute
dup 3 = if drop 2 else \ zero page
dup 4 = if drop 3 else \ abs,x
dup 5 = if drop 2 else \ zpg,x
dup 6 = if drop 2 else \ ind,x
dup 7 = if drop 3 else \ abs(ind,x)
dup 8 = if drop 2 else \ (ind),y
dup 9 = if drop 2 else \ (zpg)
dup A = if drop 3 else \ (abs)
dup B = if drop 3 else \ abs,y
C = if 2 else \ zpg,y
1 then then then then then then then then then then then then then
;
: .$ ( num size -- ) \ print num as a size hex number
\ assumes size is either 2 or 4
2 = if
dup 10 < if 30 emit 1 .r else 2 .r then
else
dup 10 < if 30 emit 30 emit 30 emit 1 .r else
dup 100 < if 30 emit 30 emit 2 .r else
dup 1000 < if 30 emit 3 .r else 4 .r then then then
then ;
: outHex ( size -- ) \ output hex data
listAddr @ $@ 2 .$ space \ all are at least one byte
dup 1 = if drop space space space space space else
dup 2 = if drop \ two bytes
listAddr @ 1+ $@ 2 .$
space space space
else
3 = if \ three bytes
listAddr @ 1+ $@ 2 .$ space
listAddr @ 2+ $@ 2 .$
then
then then
space ;
variable b1 \ first data byte
variable b2 \ second data byte
: .b @ 2 .$ ; \ print a data byte
: .imm 23 emit 24 emit b1 .b ; \ immediate
: .abs 24 emit b2 .b b1 .b ; \ absolute
: .zpg 24 emit b1 .b ; \ zero page
: .abx 24 emit b2 .b b1 .b 2C emit 58 emit ; \ absolute,x
: .zpx 24 emit b1 .b 2C emit 58 emit ; \ zero page,x
: .zix 28 emit 24 emit b1 .b 2C emit 58 emit 29 emit ; \ ($33,X)
: .aix 28 emit 24 emit b2 .b b1 .b 2C emit 58 emit 29 emit ; \ ($FDED,X)
: .ziy 28 emit 24 emit b1 .b 29 emit 2C emit 59 emit ; \ ($33),Y
: .zpi 28 emit 24 emit b1 .b 29 emit ; \ ($33)
: .abi 28 emit 24 emit b2 .b b1 .b 29 emit ; \ ($FDED)
: .aby 24 emit b2 .b b1 .b 2C emit 59 emit ; \ $FDED,Y
: .zpy 24 emit b1 .b 2C emit 59 emit ; \ $33,Y
: printMode ( mode -- ) \ output instruction data
listAddr @ 1+ $@ b1 ! listAddr @ 2+ $@ b2 ! \ save data bytes
dup 0 = if drop else \ implied
dup 1 = if drop .imm else \ immediate
dup 2 = if drop .abs else \ absolute
dup 3 = if drop .zpg else \ zero page
dup 4 = if drop .abx else \ absolute,x
dup 5 = if drop .zpx else \ zero page,x
dup 6 = if drop .zix else \ zero page indirect x
dup 7 = if drop .aix else \ absolute indirect x
dup 8 = if drop .ziy else \ zero page indirect y
dup 9 = if drop .zpi else \ zero page indirect
dup A = if drop .abi else \ absolute indirect
dup B = if drop .aby else \ absolute y
C = if drop .zpy else \ zero page y
then then then then then then then then then then then
then then
;
: listMem \ 'L' - list memory
buff 1+ c@ 0 <> if
buff 1+ 0 getNumber listAddr !
then
0 lines !
begin
lines @ 16 <
while
listAddr @ 4 .$ 2D emit space \ print address
listAddr @ $@ 4 * list + 3 + c@ \ get mode (2 * 16-bit) ****
instSize outHex \ print hex codes
listAddr @ $@ 4 * list + 2+ c@ \ get instruction (2 *)
printLa ' $00 , \ 60
' $64 , ' $65 , ' $66 , ' $00 , \ 64
' $68 , ' $69 , ' $6A , ' $00 , \ 68
' $6C , ' $6D , ' $6E , ' $00 , \ 6C
' $70 , ' $71 , ' $72 , ' $00 , \ 70
' $74 , ' $75 , ' $76 , ' $00 , \ 74
' $78 , ' $79 , ' $7A , ' $00 , \ 78
' $7C , ' $7D , ' $7E , ' $00 , \ 7C
' $80 , ' $81 , ' $00 , ' $00 , \ 80
' $84 , ' $85 , ' $86 , ' $00 , \ 84
' $88 , ' $89 , ' $8A , ' $00 , \ 88
' $8C , ' $8D , ' $8E , ' $00 , \ 8C
' $90 , ' $91 , ' $92 , ' $00 , \ 90
' $94 , ' $95 , ' $96 , ' $00 , \ 94
' $98 , ' $99 , ' $9A , ' $00 , \ 98
' $9C , ' $9D , ' $9E , ' $00 , \ 9C
' $A0 , ' $A1 , ' $A2 , ' $00 , \ A0
' $A4 , ' $A5 , ' $A6 , ' $00 , \ A4
' $A8 , ' $A9 , ' $AA , ' $00 , \ A8
' $AC , ' $AD , ' $AE , ' $00 , \ AC
' $B0 , ' $B1 , ' $B2 , ' $00 , \ B0
' $B4 , ' $B5 , ' $B6 , ' $00 , \ B4
' $B8 , ' $B9 , ' $BA , ' $00 , \ B8
' $BC , ' $BD , ' $BE , ' $00 , \ BC
' $C0 , ' $C1 , ' $00 , ' $C3 , \ C0, C3 = set startup word
' $C4 , ' $C5 , ' $C6 , ' $C7 , \ C4, C7 = hex output trap
' $C8 , ' $C9 , ' $CA , ' $CB , \ C8, CB = random number
' $CC , ' $CD , ' $CE , ' $CF , \ CC, CF = "system monitor"
' $D0 , ' $D1 , ' $D2 , ' $D3 , \ D0, D3 = mouse
' $00 , ' $D5 , ' $D6 , ' $D7 , \ D4, D7 = plot
' $D8 , ' $D9 , ' $DA , ' $DB , \ D8, DB = CH trap
' $00 , ' $DD , ' $DE , ' $DF , \ DC, DF = CV trap
' $E0 , ' $E1 , ' $00 , ' $E3 , \ E0, E3 = color
' $E4 , ' $E5 , ' $E6 , ' $E7 , \ E4, E7 = $C300 trap
' $E8 , ' $E9 , ' $EA , ' $EB , \ E8, EB = LineTo
' $EC , ' $ED , ' $EE , ' $EF , \ EC, EF = MoveTo
' $F0 , ' $F1 , ' $F2 , ' $F3 , \ F0, F3 = cout trap
' $00 , ' $F5 , ' $F6 , ' $F7 , \ F4, F7 = output cr trap
' $F8 , ' $F9 , ' $FA , ' $FB , \ F8, FB = getkey trap
' $00 , ' $FD , ' $FE , ' $FF , \ FC, FF = ProDOS trap
\ Microprocessor Simulator Words
: initialize
1FF S ! \ system stack grows downward
FF BF00 $! \ set ProDOS trap
2000 PC ! \ set program counter to startup address: QForth start
1 24 $! \ start at home position
1 25 $!
0 $0000 10018 + ! \ zero startup word address
\ patches to QForth
0BE 23F9 $! \ change prompt from ':' to '>'
00 23F4 $! \ no return before each GETLN
01 2941 $! \ no cr on startup message
0DF 3A8C $! 60 3A8D $! \ patch CV
0DB 3A9A $! 60 3A9B $! \ patch CH
A2 3C79 $! \ patch to fix file buffer error in original QForth!!
9E 3C7A $! \ as above
60 2A6C $! \ exit 'read' quickly, skip filling buffer with blanks
60 2A89 $! \ skip clearing high data bit
\ patches to ProDOS and monitor routines
0B2 BF98 $! \ MACHID = Apple //e, 128k, 80-col., no clock
60 FC22 $! \ BASCALC, return
60 FE89 $! \ IN#0
60 FE93 $! \ PR#0
0E7 C300 $! 60 C301 $! \ trap 80-col. setup
0FB FD0C $! 60 FD0D $! \ trap getkey
0F7 FD8B $! 60 FD8C $! \ trap output cr
0F3 FDED $! 60 FDEE $! \ trap cout
0C7 FDDA $! 60 FDDB $! \ trap hex output
0F0 FFFE $! FF FFFF $! \ address of BRK routine
0CF FFF0 $! 60 FFF1 $! \ "system monitor"
\ special additions to QForth
0EF FFA0 $! 60 FFA1 $! \ !pen
0EB FFB0 $! 60 FFB1 $! \ -to
0E3 FFC0 $! 60 FFC1 $! \ color
0D7 FFD0 $! 60 FFD1 $! \ plot
0D3 FFE0 $! 60 FFE1 $! \ mouse
0CB FF90 $! 60 FF91 $! \ random number in FF8E and FF8F
0C3 FF80 $! 60 FF81 $! \ set startup
;
: >P \ get current flag settings
#N @v 80 * #V @v 40 * + #D @v 8 * + #I @v 4 * + #Z @v 2 * + #C @v + ;
: P> \ restore flag settings
dup 80 and 0= if #N unset else #N set then
dup 40 and 0= if #V unset else #V set then
dup 8 and 0= if #D unset else #D set then
dup 4 and 0= if #I unset else #I set then
dup 2 and 0= if #Z unset else #Z set then